home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / AmigaOS / ether_amiga.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-02  |  18.0 KB  |  710 lines

  1. /*
  2.  *  ether_amiga.cpp - Ethernet device driver, AmigaOS specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <exec/errors.h>
  24. #include <dos/dos.h>
  25. #include <dos/dosextens.h>
  26. #include <dos/dostags.h>
  27. #include <devices/sana2.h>
  28. #include <proto/exec.h>
  29. #include <proto/dos.h>
  30.  
  31. #include "sysdeps.h"
  32. #include "cpu_emulation.h"
  33. #include "main.h"
  34. #include "prefs.h"
  35. #include "user_strings.h"
  36. #include "macos_util.h"
  37. #include "ether.h"
  38. #include "ether_defs.h"
  39.  
  40. #define DEBUG 0
  41. #include "debug.h"
  42.  
  43. #define MONITOR 0
  44.  
  45.  
  46. // These messages are sent to the network process
  47. const uint32 MSG_CLEANUP = 'clea';            // Remove all protocols
  48. const uint32 MSG_ADD_MULTI = 'addm';        // Add multicast address
  49. const uint32 MSG_DEL_MULTI = 'delm';        // Add multicast address
  50. const uint32 MSG_ATTACH_PH = 'atph';        // Attach protocol handler
  51. const uint32 MSG_DETACH_PH = 'deph';        // Attach protocol handler
  52. const uint32 MSG_WRITE = 'writ';            // Write packet
  53.  
  54. struct NetMessage : public Message {
  55.     NetMessage(uint32 what_, const struct MsgPort *reply_port)
  56.     {
  57.         what = what_;
  58.         mn_ReplyPort = (struct MsgPort *)reply_port;
  59.         mn_Length = sizeof(*this);
  60.     }
  61.     uint32 what;
  62.     uint32 pointer;
  63.     uint16 type;
  64.     int16 result;
  65. };
  66.  
  67.  
  68. // List of attached protocols
  69. static const int NUM_READ_REQUESTS = 32;    // Number of read requests that are sent to device in advance
  70.  
  71. struct NetProtocol : public Node {
  72.     struct IOSana2Req read_io[NUM_READ_REQUESTS];
  73.     uint8 read_buf[NUM_READ_REQUESTS][1518];    // 14 bytes header, 1500 bytes data, 4 bytes CRC
  74.     uint16 type;
  75.     uint32 handler;
  76. };
  77.  
  78. static struct List prot_list;
  79.  
  80.  
  81. // Global variables
  82. static struct Process *net_proc = NULL;        // Network device handler process
  83. static bool proc_error;                        // Flag: process didn't initialize
  84. static struct MsgPort *proc_port = NULL;    // Message port of process, for communication with main task
  85. static struct MsgPort *reply_port = NULL;    // Reply port for communication with process
  86. static struct MsgPort *read_port = NULL;    // Reply port for read IORequests (set up and owned by network process)
  87.  
  88. static bool write_done = false;                // Flag: write request done
  89.  
  90. extern struct Task *MainTask;                // Pointer to main task (from main_amiga.cpp)
  91.  
  92.  
  93. // Prototypes
  94. static void net_func(void);
  95.  
  96.  
  97. /*
  98.  *  Send message to network process
  99.  */
  100.  
  101. static int16 send_to_proc(uint32 what, uint32 pointer = 0, uint16 type = 0)
  102. {
  103.     D(bug("sending %08lx to net_proc\n", what));
  104.     NetMessage msg(what, reply_port);
  105.     msg.pointer = pointer;
  106.     msg.type = type;
  107.     PutMsg(proc_port, &msg);
  108.     WaitPort(reply_port);
  109.     GetMsg(reply_port);
  110.     D(bug(" sent\n"));
  111.     return msg.result;
  112. }
  113.  
  114.  
  115. /*
  116.  *  Initialization
  117.  */
  118.  
  119. void EtherInit(void)
  120. {
  121.     // Do nothing if no Ethernet device specified
  122.     if (PrefsFindString("ether") == NULL)
  123.         return;
  124.  
  125.     // Initialize protocol list
  126.     NewList(&prot_list);
  127.  
  128.     // Create message port
  129.     reply_port = CreateMsgPort();
  130.     if (reply_port == NULL)
  131.         goto open_error;
  132.     D(bug("signal mask %08lx\n", 1 << reply_port->mp_SigBit));
  133.  
  134.     // Start process
  135.     proc_error = false;
  136.     SetSignal(0, SIGF_SINGLE);
  137.     net_proc = CreateNewProcTags(
  138.         NP_Entry, (ULONG)net_func,
  139.         NP_Name, (ULONG)"Basilisk II Ethernet Task",
  140.         NP_Priority, 1,
  141.         TAG_END    
  142.     );
  143.     if (net_proc == NULL)
  144.         goto open_error;
  145.  
  146.     // Wait for signal from process
  147.     Wait(SIGF_SINGLE);
  148.  
  149.     // Initialization error? Then bail out
  150.     if (proc_error)
  151.         goto open_error;
  152.  
  153.     // Everything OK
  154.     net_open = true;
  155.     return;
  156.  
  157. open_error:
  158.     net_proc = NULL;
  159.     if (reply_port) {
  160.         DeleteMsgPort(reply_port);
  161.         reply_port = NULL;
  162.     }
  163. }
  164.  
  165.  
  166. /*
  167.  *  Deinitialization
  168.  */
  169.  
  170. void EtherExit(void)
  171. {
  172.     // Stop process
  173.     if (net_proc) {
  174.         SetSignal(0, SIGF_SINGLE);
  175.         Signal(&net_proc->pr_Task, SIGBREAKF_CTRL_C);
  176.         Wait(SIGF_SINGLE);
  177.     }
  178.  
  179.     // Delete reply port
  180.     if (reply_port) {
  181.         DeleteMsgPort(reply_port);
  182.         reply_port = NULL;
  183.     }
  184. }
  185.  
  186.  
  187. /*
  188.  *  Reset
  189.  */
  190.  
  191. void EtherReset(void)
  192. {
  193.     // Remove all protocols
  194.     if (net_open)
  195.         send_to_proc(MSG_CLEANUP);
  196. }
  197.  
  198.  
  199. /*
  200.  *  Add multicast address
  201.  */
  202.  
  203. int16 ether_add_multicast(uint32 pb)
  204. {
  205.     return send_to_proc(MSG_ADD_MULTI, pb);
  206. }
  207.  
  208.  
  209. /*
  210.  *  Delete multicast address
  211.  */
  212.  
  213. int16 ether_del_multicast(uint32 pb)
  214. {
  215.     return send_to_proc(MSG_DEL_MULTI, pb);
  216. }
  217.  
  218.  
  219. /*
  220.  *  Attach protocol handler
  221.  */
  222.  
  223. int16 ether_attach_ph(uint16 type, uint32 handler)
  224. {
  225.     return send_to_proc(MSG_ATTACH_PH, handler, type);
  226. }
  227.  
  228.  
  229. /*
  230.  *  Detach protocol handler
  231.  */
  232.  
  233. int16 ether_detach_ph(uint16 type)
  234. {
  235.     return send_to_proc(MSG_DETACH_PH, type);
  236. }
  237.  
  238.  
  239. /*
  240.  *  Transmit raw ethernet packet
  241.  */
  242.  
  243. int16 ether_write(uint32 wds)
  244. {
  245.     send_to_proc(MSG_WRITE, wds);
  246.     return 1;    // Command in progress
  247. }
  248.  
  249.  
  250. /*
  251.  *  Remove protocol from protocol list
  252.  */
  253.  
  254. static void remove_protocol(NetProtocol *p)
  255. {
  256.     // Remove from list
  257.     Forbid();
  258.     Remove(p);
  259.     Permit();
  260.  
  261.     // Cancel read requests
  262.     for (int i=0; i<NUM_READ_REQUESTS; i++) {
  263.         AbortIO((struct IORequest *)(p->read_io + i));
  264.         WaitIO((struct IORequest *)(p->read_io + i));
  265.     }
  266.  
  267.     // Free protocol struct
  268.     FreeMem(p, sizeof(NetProtocol));
  269. }
  270.  
  271.  
  272. /*
  273.  *  Remove all protocols
  274.  */
  275.  
  276. static void remove_all_protocols(void)
  277. {
  278.     NetProtocol *n = (NetProtocol *)prot_list.lh_Head, *next;
  279.     while ((next = (NetProtocol *)n->ln_Succ) != NULL) {
  280.         remove_protocol(n);
  281.         n = next;
  282.     }
  283. }
  284.  
  285.  
  286. /*
  287.  *  Copy received network packet to Mac side
  288.  */
  289.  
  290. static __saveds __regargs LONG copy_to_buff(uint8 *to /*a0*/, uint8 *from /*a1*/, uint32 packet_len /*d0*/)
  291. {
  292.     D(bug("CopyToBuff to %08lx, from %08lx, size %08lx\n", to, from, packet_len));
  293.  
  294.     // It would be more efficient (and take up less memory) if we
  295.     // could invoke the packet handler from here. But we don't know
  296.     // in what context we run, so calling Execute68k() would not be
  297.     // a good idea, and even worse, we might run inside a hardware
  298.     // interrupt, so we can't even trigger a Basilisk interrupt from
  299.     // here and wait for its completion.
  300.     CopyMem(from, to, packet_len);
  301. #if MONITOR
  302.     bug("Receiving Ethernet packet:\n");
  303.     for (int i=0; i<packet_len; i++) {
  304.         bug("%02lx ", from[i]);
  305.     }
  306.     bug("\n");
  307. #endif
  308.     return 1;
  309. }
  310.  
  311.  
  312. /*
  313.  *  Copy data from Mac WDS to outgoing network packet
  314.  */
  315.  
  316. static __saveds __regargs LONG copy_from_buff(uint8 *to /*a0*/, char *wds /*a1*/, uint32 packet_len /*d0*/)
  317. {
  318.     D(bug("CopyFromBuff to %08lx, wds %08lx, size %08lx\n", to, wds, packet_len));
  319. #if MONITOR
  320.     bug("Sending Ethernet packet:\n");
  321. #endif
  322.     for (;;) {
  323.         int len = ReadMacInt16((uint32)wds);
  324.         if (len == 0)
  325.             break;
  326. #if MONITOR
  327.         uint8 *adr = Mac2HostAddr(ReadMacInt32((uint32)wds + 2));
  328.         for (int i=0; i<len; i++) {
  329.             bug("%02lx ", adr[i]);
  330.         }
  331. #endif
  332.         CopyMem(Mac2HostAddr(ReadMacInt32((uint32)wds + 2)), to, len);
  333.         to += len;
  334.         wds += 6;
  335.     }
  336. #if MONITOR
  337.     bug("\n");
  338. #endif
  339.     return 1;
  340. }
  341.  
  342.  
  343. /*
  344.  *  Process for communication with the Ethernet device
  345.  */
  346.  
  347. static __saveds void net_func(void)
  348. {
  349.     const char *str;
  350.     BYTE od_error;
  351.     struct MsgPort *write_port = NULL, *control_port = NULL;
  352.     struct IOSana2Req *write_io = NULL, *control_io = NULL;
  353.     bool opened = false;
  354.     ULONG read_mask = 0, write_mask = 0, proc_port_mask = 0;
  355.     struct Sana2DeviceQuery query_data = {sizeof(Sana2DeviceQuery)};
  356.     ULONG buffer_tags[] = {
  357.         S2_CopyToBuff, (uint32)copy_to_buff,
  358.         S2_CopyFromBuff, (uint32)copy_from_buff,
  359.         TAG_END
  360.     };
  361.  
  362.     // Default: error occured
  363.     proc_error = true;
  364.  
  365.     // Create message port for communication with main task
  366.     proc_port = CreateMsgPort();
  367.     if (proc_port == NULL)
  368.         goto quit;
  369.     proc_port_mask = 1 << proc_port->mp_SigBit;
  370.  
  371.     // Create message ports for device I/O
  372.     read_port = CreateMsgPort();
  373.     if (read_port == NULL)
  374.         goto quit;
  375.     read_mask = 1 << read_port->mp_SigBit;
  376.     write_port = CreateMsgPort();
  377.     if (write_port == NULL)
  378.         goto quit;
  379.     write_mask = 1 << write_port->mp_SigBit;
  380.     control_port = CreateMsgPort();
  381.     if (control_port == NULL)
  382.         goto quit;
  383.  
  384.     // Create control IORequest
  385.     control_io = (struct IOSana2Req *)CreateIORequest(control_port, sizeof(struct IOSana2Req));
  386.     if (control_io == NULL)
  387.         goto quit;
  388.     control_io->ios2_Req.io_Message.mn_Node.ln_Type = 0;    // Avoid CheckIO() bug
  389.  
  390.     // Parse device name
  391.     char dev_name[256];
  392.     ULONG dev_unit;
  393.  
  394.     str = PrefsFindString("ether");
  395.     if (str)
  396.         {
  397.         const char *FirstSlash = strchr(str, '/');
  398.         const char *LastSlash = strrchr(str, '/');
  399.  
  400.         if (FirstSlash && FirstSlash && FirstSlash != LastSlash)
  401.             {
  402.             // Device name contains path, i.e. "Networks/xyzzy.device"
  403.             const char *lp = str;
  404.             char *dp = dev_name;
  405.  
  406.             while (lp != LastSlash)
  407.                 *dp++ = *lp++;
  408.             *dp = '\0';
  409.  
  410.             if (strlen(dev_name) < 1)
  411.                 goto quit;
  412.  
  413.             if (1 != sscanf(LastSlash, "/%ld", &dev_unit))
  414.                 goto quit;
  415.  
  416. //            printf("dev=<%s> unit=%d\n", dev_name, dev_unit);
  417.             }
  418.         else
  419.             {
  420.             if (2 != sscanf(str, "%[^/]/%ld", dev_name, &dev_unit))
  421.                 goto quit;
  422.             }
  423.         }
  424.     else
  425.         goto quit;
  426.  
  427.     // Open device
  428.     control_io->ios2_BufferManagement = buffer_tags;
  429.     od_error = OpenDevice((UBYTE *)dev_name, dev_unit, (struct IORequest *)control_io, 0);
  430.     if (0 != od_error || control_io->ios2_Req.io_Device == 0)
  431.         {
  432.         printf("WARNING: OpenDevice(<%s>, unit=%d) returned error %d)\n", (UBYTE *)dev_name, dev_unit, od_error);
  433.         goto quit;
  434.         }
  435.     opened = true;
  436.  
  437.     // Is it Ethernet?
  438.     control_io->ios2_Req.io_Command = S2_DEVICEQUERY;
  439.     control_io->ios2_StatData = (void *)&query_data;
  440.     DoIO((struct IORequest *)control_io);
  441.     if (control_io->ios2_Req.io_Error)
  442.         goto quit;
  443.     if (query_data.HardwareType != S2WireType_Ethernet) {
  444.         WarningAlert(GetString(STR_NOT_ETHERNET_WARN));
  445.         goto quit;
  446.     }
  447.  
  448.     // Yes, create IORequest for writing
  449.     write_io = (struct IOSana2Req *)CreateIORequest(write_port, sizeof(struct IOSana2Req));
  450.     if (write_io == NULL)
  451.         goto quit;
  452.     memcpy(write_io, control_io, sizeof(struct IOSana2Req));
  453.     write_io->ios2_Req.io_Message.mn_Node.ln_Type = 0;    // Avoid CheckIO() bug
  454.     write_io->ios2_Req.io_Message.mn_ReplyPort = write_port;
  455.  
  456.     // Configure Ethernet
  457.     control_io->ios2_Req.io_Command = S2_GETSTATIONADDRESS;
  458.     DoIO((struct IORequest *)control_io);
  459.     memcpy(ether_addr, control_io->ios2_DstAddr, 6);
  460.     memcpy(control_io->ios2_SrcAddr, control_io->ios2_DstAddr, 6);
  461.     control_io->ios2_Req.io_Command = S2_CONFIGINTERFACE;
  462.     DoIO((struct IORequest *)control_io);
  463.     D(bug("Ethernet address %08lx %08lx\n", *(uint32 *)ether_addr, *(uint16 *)(ether_addr + 4)));
  464.  
  465.     // Initialization went well, inform main task
  466.     proc_error = false;
  467.     Signal(MainTask, SIGF_SINGLE);
  468.  
  469.     // Main loop
  470.     for (;;) {
  471.  
  472.         // Wait for I/O and messages (CTRL_C is used for quitting the task)
  473.         ULONG sig = Wait(proc_port_mask | read_mask | write_mask | SIGBREAKF_CTRL_C);
  474.  
  475.         // Main task wants to quit us
  476.         if (sig & SIGBREAKF_CTRL_C)
  477.             break;
  478.  
  479.         // Main task sent a command to us
  480.         if (sig & proc_port_mask) {
  481.             struct NetMessage *msg;
  482.             while (msg = (NetMessage *)GetMsg(proc_port)) {
  483.                 D(bug("net_proc received %08lx\n", msg->what));
  484.                 switch (msg->what) {
  485.                     case MSG_CLEANUP:
  486.                         remove_all_protocols();
  487.                         break;
  488.  
  489.                     case MSG_ADD_MULTI:
  490.                         control_io->ios2_Req.io_Command = S2_ADDMULTICASTADDRESS;
  491.                         Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
  492.                         DoIO((struct IORequest *)control_io);
  493.                         if (control_io->ios2_Req.io_Error == S2ERR_NOT_SUPPORTED) {
  494.                             WarningAlert(GetString(STR_NO_MULTICAST_WARN));
  495.                             msg->result = noErr;
  496.                         } else if (control_io->ios2_Req.io_Error)
  497.                             msg->result = eMultiErr;
  498.                         else
  499.                             msg->result = noErr;
  500.                         break;
  501.  
  502.                     case MSG_DEL_MULTI:
  503.                         control_io->ios2_Req.io_Command = S2_DELMULTICASTADDRESS;
  504.                         Mac2Host_memcpy(control_io->ios2_SrcAddr, msg->pointer + eMultiAddr, 6);
  505.                         DoIO((struct IORequest *)control_io);
  506.                         if (control_io->ios2_Req.io_Error)
  507.                             msg->result = eMultiErr;
  508.                         else
  509.                             msg->result = noErr;
  510.                         break;
  511.  
  512.                     case MSG_ATTACH_PH: {
  513.                         uint16 type = msg->type;
  514.                         uint32 handler = msg->pointer;
  515.  
  516.                         // Protocol of that type already installed?
  517.                         NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
  518.                         while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
  519.                             if (p->type == type) {
  520.                                 msg->result = lapProtErr;
  521.                                 goto reply;
  522.                             }
  523.                             p = next;
  524.                         }
  525.  
  526.                         // Allocate NetProtocol, set type and handler
  527.                         p = (NetProtocol *)AllocMem(sizeof(NetProtocol), MEMF_PUBLIC);
  528.                         if (p == NULL) {
  529.                             msg->result = lapProtErr;
  530.                             goto reply;
  531.                         }
  532.                         p->type = type;
  533.                         p->handler = handler;
  534.  
  535.                         // Set up and submit read requests
  536.                         for (int i=0; i<NUM_READ_REQUESTS; i++) {
  537.                             memcpy(p->read_io + i, control_io, sizeof(struct IOSana2Req));
  538.                             p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Name = (char *)p;    // Hide pointer to NetProtocol in node name
  539.                             p->read_io[i].ios2_Req.io_Message.mn_Node.ln_Type = 0;            // Avoid CheckIO() bug
  540.                             p->read_io[i].ios2_Req.io_Message.mn_ReplyPort = read_port;
  541.                             p->read_io[i].ios2_Req.io_Command = CMD_READ;
  542.                             p->read_io[i].ios2_PacketType = type;
  543.                             p->read_io[i].ios2_Data = p->read_buf[i];
  544.                             p->read_io[i].ios2_Req.io_Flags = SANA2IOF_RAW;
  545.                             BeginIO((struct IORequest *)(p->read_io + i));
  546.                         }
  547.  
  548.                         // Add protocol to list
  549.                         AddTail(&prot_list, p);
  550.  
  551.                         // Everything OK
  552.                         msg->result = noErr;
  553.                         break;
  554.                     }
  555.  
  556.                     case MSG_DETACH_PH: {
  557.                         uint16 type = msg->type;
  558.                         msg->result = lapProtErr;
  559.                         NetProtocol *p = (NetProtocol *)prot_list.lh_Head, *next;
  560.                         while ((next = (NetProtocol *)p->ln_Succ) != NULL) {
  561.                             if (p->type == type) {
  562.                                 remove_protocol(p);
  563.                                 msg->result = noErr;
  564.                                 break;
  565.                             }
  566.                             p = next;
  567.                         }
  568.                         break;
  569.                     }
  570.  
  571.                     case MSG_WRITE: {
  572.                         // Get pointer to Write Data Structure
  573.                         uint32 wds = msg->pointer;
  574.                         write_io->ios2_Data = (void *)wds;
  575.  
  576.                         // Calculate total packet length
  577.                         long len = 0;
  578.                         uint32 tmp = wds;
  579.                         for (;;) {
  580.                             int16 w = ReadMacInt16(tmp);
  581.                             if (w == 0)
  582.                                 break;
  583.                             len += w;
  584.                             tmp += 6;
  585.                         }
  586.                         write_io->ios2_DataLength = len;
  587.  
  588.                         // Get destination address, set source address
  589.                         uint32 hdr = ReadMacInt32(wds + 2);
  590.                         Mac2Host_memcpy(write_io->ios2_DstAddr, hdr, 6);
  591.                         Host2Mac_memcpy(hdr + 6, ether_addr, 6);
  592.  
  593.                         // Get packet type
  594.                         uint32 type = ReadMacInt16(hdr + 12);
  595.                         if (type <= 1500)
  596.                             type = 0;        // 802.3 packet
  597.                         write_io->ios2_PacketType = type;
  598.  
  599.                         // Multicast/broadcard packet?
  600.                         if (write_io->ios2_DstAddr[0] & 1) {
  601.                             if (*(uint32 *)(write_io->ios2_DstAddr) == 0xffffffff && *(uint16 *)(write_io->ios2_DstAddr + 4) == 0xffff)
  602.                                 write_io->ios2_Req.io_Command = S2_BROADCAST;
  603.                             else
  604.                                 write_io->ios2_Req.io_Command = S2_MULTICAST;
  605.                         } else
  606.                             write_io->ios2_Req.io_Command = CMD_WRITE;
  607.  
  608.                         // Send packet
  609.                         write_done = false;
  610.                         write_io->ios2_Req.io_Flags = SANA2IOF_RAW;
  611.                         BeginIO((IORequest *)write_io);
  612.                         break;
  613.                     }
  614.                 }
  615. reply:            D(bug(" net_proc replying\n"));
  616.                 ReplyMsg(msg);
  617.             }
  618.         }
  619.  
  620.         // Packet received
  621.         if (sig & read_mask) {
  622.             D(bug(" packet received, triggering Ethernet interrupt\n"));
  623.             SetInterruptFlag(INTFLAG_ETHER);
  624.             TriggerInterrupt();
  625.         }
  626.  
  627.         // Packet write completed
  628.         if (sig & write_mask) {
  629.             GetMsg(write_port);
  630.             WriteMacInt32(ether_data + ed_Result, write_io->ios2_Req.io_Error ? excessCollsns : 0);
  631.             write_done = true;
  632.             D(bug(" packet write done, triggering Ethernet interrupt\n"));
  633.             SetInterruptFlag(INTFLAG_ETHER);
  634.             TriggerInterrupt();
  635.         }
  636.     }
  637. quit:
  638.  
  639.     // Close everything
  640.     remove_all_protocols();
  641.     if (opened) {
  642.         if (CheckIO((struct IORequest *)write_io) == 0) {
  643.             AbortIO((struct IORequest *)write_io);
  644.             WaitIO((struct IORequest *)write_io);
  645.         }
  646.         CloseDevice((struct IORequest *)control_io);
  647.     }
  648.     if (write_io)
  649.         DeleteIORequest(write_io);
  650.     if (control_io)
  651.         DeleteIORequest(control_io);
  652.     if (control_port)
  653.         DeleteMsgPort(control_port);
  654.     if (write_port)
  655.         DeleteMsgPort(write_port);
  656.     if (read_port)
  657.         DeleteMsgPort(read_port);
  658.  
  659.     // Send signal to main task to confirm termination
  660.     Forbid();
  661.     Signal(MainTask, SIGF_SINGLE);
  662. }
  663.  
  664.  
  665. /*
  666.  *  Ethernet interrupt - activate deferred tasks to call IODone or protocol handlers
  667.  */
  668.  
  669. void EtherInterrupt(void)
  670. {
  671.     D(bug("EtherIRQ\n"));
  672.  
  673.     // Packet write done, enqueue DT to call IODone
  674.     if (write_done) {
  675.         EnqueueMac(ether_data + ed_DeferredTask, 0xd92);
  676.         write_done = false;
  677.     }
  678.  
  679.     // Call protocol handler for received packets
  680.     IOSana2Req *io;
  681.     while (io = (struct IOSana2Req *)GetMsg(read_port)) {
  682.  
  683.         // Get pointer to NetProtocol (hidden in node name)
  684.         NetProtocol *p = (NetProtocol *)io->ios2_Req.io_Message.mn_Node.ln_Name;
  685.  
  686.         // No default handler
  687.         if (p->handler == 0)
  688.             continue;
  689.  
  690.         // Copy header to RHA
  691.         Host2Mac_memcpy(ether_data + ed_RHA, io->ios2_Data, 14);
  692.         D(bug(" header %08lx%04lx %08lx%04lx %04lx\n", ReadMacInt32(ether_data + ed_RHA), ReadMacInt16(ether_data + ed_RHA + 4), ReadMacInt32(ether_data + ed_RHA + 6), ReadMacInt16(ether_data + ed_RHA + 10), ReadMacInt16(ether_data + ed_RHA + 12)));
  693.  
  694.         // Call protocol handler
  695.         M68kRegisters r;
  696.         r.d[0] = *(uint16 *)((uint32)io->ios2_Data + 12);    // Packet type
  697.         r.d[1] = io->ios2_DataLength - 18;                    // Remaining packet length (without header, for ReadPacket) (-18 because the CRC is also included)
  698.         r.a[0] = (uint32)io->ios2_Data + 14;                // Pointer to packet (host address, for ReadPacket)
  699.         r.a[3] = ether_data + ed_RHA + 14;                    // Pointer behind header in RHA
  700.         r.a[4] = ether_data + ed_ReadPacket;                // Pointer to ReadPacket/ReadRest routines
  701.         D(bug(" calling protocol handler %08lx, type %08lx, length %08lx, data %08lx, rha %08lx, read_packet %08lx\n", p->handler, r.d[0], r.d[1], r.a[0], r.a[3], r.a[4]));
  702.         Execute68k(p->handler, &r);
  703.  
  704.         // Resend IORequest
  705.         io->ios2_Req.io_Flags = SANA2IOF_RAW;
  706.         BeginIO((struct IORequest *)io);
  707.     }
  708.     D(bug(" EtherIRQ done\n"));
  709. }
  710.